home *** CD-ROM | disk | FTP | other *** search
/ QRZ! Ham Radio 1 / QRZ Ham Radio Callsign Database - December 1993.iso / ucsd / packet / tcpip / amiga / asrc29k.lha / nr4.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-01-08  |  19.2 KB  |  729 lines

  1. /* net/rom level 4 (transport) protocol implementation
  2.  * Copyright 1989 by Daniel M. Frank, W9NK.  Permission granted for
  3.  * non-commercial distribution only.
  4.  * Ported to NOS by SM0RGV, 890525.
  5.  */
  6.  
  7. #include <stdio.h>
  8. #include "global.h"
  9. #include "mbuf.h"
  10. #include "timer.h"
  11. #include "ax25.h"
  12. #include "lapb.h"
  13. #include "netrom.h"
  14. #include "nr4.h"
  15. #include <ctype.h>
  16.  
  17. #undef NR4DEBUG
  18.  
  19. /* Globals: */
  20.  
  21. /* The circuit table */
  22.  
  23. struct nr4circp Nr4circuits[NR4MAXCIRC];
  24.  
  25. /* Various limits */
  26.  
  27. unsigned short Nr4window = 4;        /* Max window to negotiate */
  28. unsigned short Nr4retries = 10;    /* Max retries */
  29. unsigned short Nr4qlimit = 2048;    /* Max bytes on receive queue */
  30.  
  31. /* Timers */
  32.  
  33. int32 Nr4irtt = 15000;            /* Initial round trip time */
  34. int32 Nr4acktime = 3000;        /* ACK delay timer */
  35. int32 Nr4choketime = 180000;        /* CHOKEd state timeout */
  36.  
  37. static void nr4ackours __ARGS((struct nr4cb *, unsigned, int));
  38. static void nr4choke __ARGS((struct nr4cb *));
  39. static void nr4gotnak __ARGS((struct nr4cb *, unsigned));
  40. static void nr4rframe __ARGS((struct nr4cb *, unsigned, struct mbuf *));
  41.  
  42. /* This function is called when a net/rom layer four frame */
  43. /* is discovered inside a datagram addressed to us */
  44.  
  45. void
  46. nr4input(hdr,bp)
  47. struct nr4hdr *hdr;
  48. struct mbuf *bp;
  49. {
  50.     struct nr4hdr rhdr;
  51.     struct nr4cb *cb, *cb2;
  52.     int op;
  53.     unsigned window;
  54.     int acceptc;        /* indicates that connection should be accepted */
  55.     int newconn;        /* indicates that this is a new incoming */
  56.                         /* connection.  You'll see. */
  57.     int gotchoke;        /* The choke flag was set in this packet */        
  58.     int i;
  59.     
  60.     op = hdr->opcode & NR4OPCODE;    /* Mask off flags */
  61.     
  62.     if(op == NR4OPCONRQ){            /* process connect request first */
  63.         acceptc = 1;
  64.         newconn = 0;
  65.  
  66.         /* These fields are sent regardless of success */
  67.         rhdr.yourindex = hdr->u.conreq.myindex;
  68.         rhdr.yourid = hdr->u.conreq.myid;
  69.  
  70.         /* Check to see if we have already received a connect */
  71.         /* request for this circuit. */
  72.         if((cb = match_n4circ(hdr->u.conreq.myindex,
  73.          hdr->u.conreq.myid,hdr->u.conreq.user,hdr->u.conreq.node))
  74.          == NULLNR4CB){    /* No existing circuit if NULL */
  75.  
  76.             /* Try to get a new circuit */
  77.             if((cb = new_n4circ()) == NULLNR4CB)
  78.                 acceptc = 0;
  79.             /* See if we have any listening sockets */
  80.             for(i = 0; i < NR4MAXCIRC; i++){
  81.                 if((cb2 = Nr4circuits[i].ccb) == NULLNR4CB)
  82.                 continue;/* not an open circuit */
  83.                 if(cb2->state == NR4STLISTEN)
  84.                     /* A listener was found */
  85.                     break;
  86.             }
  87.             if(i == NR4MAXCIRC){ /* We are refusing connects */
  88.                 acceptc = 0;
  89.                 free_n4circ(cb);
  90.             }
  91.             if(acceptc){
  92.                 /* Load the listeners settings */
  93.                 cb->clone = cb2->clone;
  94.                 cb->user = cb2->user;
  95.                 cb->t_upcall = cb2->t_upcall;
  96.                 cb->s_upcall = cb2->s_upcall;
  97.                 cb->r_upcall = cb2->r_upcall;
  98.                 ASSIGN(cb->local,cb2->local);
  99.  
  100.                 /* Window is set to min of the offered
  101.                  * and local windows
  102.                  */
  103.                 window = hdr->u.conreq.window > Nr4window ?
  104.                          Nr4window : hdr->u.conreq.window;
  105.  
  106.                 if(init_nr4window(cb, window) == -1){
  107.                     free_n4circ(cb);
  108.                     acceptc = 0;
  109.                 } else {
  110.                     /* Set up control block */
  111.                     cb->yournum = hdr->u.conreq.myindex;
  112.                     cb->yourid = hdr->u.conreq.myid;
  113.                     memcpy(cb->remote.user,
  114.                            hdr->u.conreq.user,AXALEN);
  115.                     memcpy(cb->remote.node,
  116.                            hdr->u.conreq.node,AXALEN);
  117.                     /* Default round trip time */
  118.                     cb->srtt = Nr4irtt;
  119.                     /* set up timers, window pointers */
  120.                     nr4defaults(cb);
  121.                     cb->state = NR4STDISC;
  122.                     newconn = 1;
  123.                 } /* End if window successfully allocated */
  124.             }    /* End if new circuit available */
  125.          } /* End if no existing circuit matching parameters */
  126.  
  127.         /* Now set up response */
  128.         if(!acceptc){
  129.             rhdr.opcode = NR4OPCONAK | NR4CHOKE;/* choke means reject */
  130.             rhdr.u.conack.myindex = 0;
  131.             rhdr.u.conack.myid = 0;
  132.             rhdr.u.conack.window = 0;
  133.         } else {
  134.             rhdr.opcode = NR4OPCONAK;
  135.             rhdr.u.conack.myindex = cb->mynum;
  136.             rhdr.u.conack.myid = cb->myid;
  137.             rhdr.u.conack.window = cb->window;
  138.         }
  139.         nr4sframe(hdr->u.conreq.node, &rhdr, NULLBUF);
  140.  
  141.         /* Why, you ask, do we wait until now for the state change
  142.          * upcall?  Well, it's like this:  if the state change triggers
  143.          * something like the mailbox to send its banner, the banner
  144.          * would have gone out *before* the conn ack if we'd done this
  145.          * in the code above.  This is what happens when you don't plan
  146.          * too well.  Learn from my mistakes :-)
  147.          */
  148.         if(newconn)
  149.             nr4state(cb, NR4STCON);/* connected (no 3-way handshake) */
  150.             
  151.         free_p(bp);
  152.         return;
  153.     } /* end connect request code */
  154.  
  155.     /* validate circuit number */
  156.     if((cb = get_n4circ(hdr->yourindex, hdr->yourid)) == NULLNR4CB){
  157.         free_p(bp);
  158.         return;
  159.     }
  160.  
  161.     /* Check for choke flag */
  162.     if(hdr->opcode & NR4CHOKE)
  163.         gotchoke = 1;
  164.     else
  165.         gotchoke = 0;
  166.     
  167.     /* Here's where the interesting stuff gets done */
  168.     switch(cb->state){
  169.     case NR4STCPEND:
  170.         switch(op){
  171.         case NR4OPCONAK:
  172.             /* Save the round trip time for later use */
  173.             i = dur_timer(&cb->tcd) - read_timer(&cb->tcd);
  174.             stop_timer(&cb->tcd);
  175.             if(gotchoke){        /* connect rejected */
  176.                 cb->dreason = NR4RREFUSED;
  177.                 nr4state(cb, NR4STDISC);
  178.                 break;
  179.             }
  180.             cb->yournum = hdr->u.conack.myindex;
  181.             cb->yourid = hdr->u.conack.myid;
  182.             window = hdr->u.conack.window > Nr4window ?
  183.                      Nr4window : hdr->u.conack.window;
  184.  
  185.             if(init_nr4window(cb, window) == -1){
  186.                 cb->dreason = NR4RRESET;
  187.                 nr4state(cb, NR4STDISC);
  188.             } else {
  189.                 nr4defaults(cb);    /* set up timers, window pointers */
  190.                 
  191.                 if(cb->cdtries == 1)    /* No retries */
  192.                     /* Use measured rtt */
  193.                     cb->srtt = i * MSPTICK;
  194.                 else
  195.                     /* else use default */
  196.                     cb->srtt = Nr4irtt;
  197.                     
  198.                 nr4state(cb, NR4STCON);
  199.                 nr4output(cb);        /* start sending anything on the txq */
  200.             }
  201.             break;
  202.         default:
  203.             /* We can't respond to anything else without
  204.              * Their ID and index
  205.              */
  206.               free_p(bp);
  207.             return;
  208.         }
  209.         break;
  210.     case NR4STCON:
  211.         switch(op){
  212.         case NR4OPDISRQ:
  213.             /* format reply packet */
  214.             rhdr.opcode = NR4OPDISAK;
  215.             rhdr.yourindex = cb->yournum;
  216.             rhdr.yourid = cb->yourid;
  217.             nr4sframe(cb->remote.node,&rhdr,NULLBUF);
  218.             cb->dreason = NR4RREMOTE;
  219.             nr4state(cb, NR4STDISC);
  220.             break;
  221.           case NR4OPINFO:
  222.             /* Do receive frame processing */
  223.               nr4rframe(cb, hdr->u.info.txseq, bp);
  224.  
  225.             /* Reset the choke flag if no longer choked.  Processing
  226.              * the ACK will kick things off again.
  227.              */
  228.             if(cb->choked && !gotchoke){
  229.                 stop_timer(&cb->tchoke);
  230.                 cb->choked = 0;
  231.             }
  232.                 
  233.             /* We delay processing the receive sequence number until
  234.              * now, because the ACK might pull more off the txq and send
  235.              * it, and we want the implied ACK in those frames to be right
  236.              *
  237.              * Only process NAKs if the choke flag is off.  It appears
  238.              * that NAKs should never be sent with choke on, by the way,
  239.              * but you never know, considering that there is no official
  240.              * standard for this protocol
  241.              */
  242.             if(hdr->opcode & NR4NAK && !gotchoke)
  243.                 nr4gotnak(cb, hdr->u.info.rxseq);
  244.  
  245.             /* We always do ACK processing, too, since the NAK of one
  246.              * packet may be the implied ACK of another.  The gotchoke
  247.              * flag is used to prevent sending any new frames, since
  248.              * we are just going to purge them next anyway if this is
  249.              * the first time we've seen the choke flag.  If we are
  250.              * already choked, this call will return immediately.
  251.              */
  252.             nr4ackours(cb, hdr->u.info.rxseq, gotchoke);
  253.  
  254.             /* If we haven't seen the choke flag before, purge the
  255.              * send window and set the timer and the flag.
  256.              */
  257.             if(!cb->choked && gotchoke)
  258.                 nr4choke(cb);
  259.             break;
  260.           case NR4OPACK:
  261.             if(cb->choked && !gotchoke){
  262.                 /* clear choke if appropriate */
  263.                 stop_timer(&cb->tchoke);
  264.                 cb->choked = 0;
  265.             }    
  266.               if(hdr->opcode & NR4NAK && !gotchoke)
  267.                 nr4gotnak(cb, hdr->u.ack.rxseq);    /* process NAKs */
  268.                 
  269.               nr4ackours(cb, hdr->u.ack.rxseq, gotchoke); /* and ACKs */
  270.  
  271.             if(!cb->choked && gotchoke)    /* First choke seen */
  272.                 nr4choke(cb);        /* Set choke status */
  273.  
  274.             break;
  275.         }
  276.         break;
  277.     case NR4STDPEND:
  278.         switch(op){
  279.         case NR4OPDISAK:
  280.               cb->dreason = NR4RNORMAL;
  281.             nr4state(cb, NR4STDISC);
  282.             break;
  283.         case NR4OPINFO:
  284.             /* We can still do receive frame processing until
  285.              * the disconnect acknowledge arrives, but we won't
  286.              * bother to process ACKs, since we've flushed our
  287.              * transmit buffers and queue already.
  288.              */
  289.               nr4rframe(cb, hdr->u.info.txseq, bp);
  290.             break;
  291.         }
  292.     }    /* End switch(state) */
  293. }
  294.  
  295.  
  296. /* Send a net/rom layer 4 frame.  bp should be NULLBUF unless the frame
  297.  * type is info.
  298.  */
  299. void
  300. nr4sframe(dest, hdr, bp)
  301. char *dest;
  302. struct nr4hdr *hdr;
  303. struct mbuf *bp;
  304. {
  305.     struct mbuf *n4b;
  306.  
  307.     if((n4b = htonnr4(hdr)) == NULLBUF){
  308.         free_p(bp);
  309.         return;
  310.     } else {
  311.         append(&n4b, bp);
  312.         nr3output(dest, n4b);
  313.     }
  314. }
  315.  
  316. /* Receive frame processing */
  317. static void
  318. nr4rframe(cb, rxseq, bp)
  319. struct nr4cb *cb;
  320. unsigned rxseq;
  321. struct mbuf *bp;
  322. {
  323.     struct nr4hdr rhdr;
  324.     unsigned window = cb->window;
  325.     unsigned rxbuf = rxseq % window;
  326.     unsigned newdata = 0;        /* whether to upcall */
  327.  
  328. #ifdef NR4DEBUG
  329.     printf("Processing received info\n");
  330. #endif
  331.  
  332.     /* If we're choked, just reset the ACK timer to blast out
  333.      * another CHOKE indication after the ackdelay
  334.      */
  335.     if(cb->qfull){
  336.         start_timer(&cb->tack);
  337.         return;
  338.     }
  339.     
  340.     /* If the frame is out of sequence, NAK it if we haven't
  341.      * already done so
  342.      */
  343.       if(rxseq != cb->rxpected && !cb->naksent){
  344. #ifdef NR4DEBUG
  345.         printf("Frame out of sequence -- expected %u, got %u.\n",
  346.                cb->rxpected, rxseq);
  347. #endif                
  348.         rhdr.opcode = NR4OPACK | NR4NAK;
  349.         rhdr.yourindex = cb->yournum;
  350.         rhdr.yourid = cb->yourid;
  351.         rhdr.u.ack.rxseq = cb->rxpected;
  352.         nr4sframe(cb->remote.node,&rhdr,NULLBUF);
  353.         
  354.         /* Now make sure we don't send any more of these until */
  355.         /* we see some good data.  Otherwise full window retransmissions */
  356.         /* would result in a flurry of NAKs */
  357.         
  358.         cb->naksent = 1;
  359.     }
  360.             
  361.     /* If this is a new frame, within the window, buffer it,
  362.      * then see what we can deliver
  363.      */
  364.     if(nr4between(cb->rxpected,rxseq,cb->rxpastwin)
  365.         && !cb->rxbufs[rxbuf].occupied){
  366. #ifdef NR4DEBUG
  367.         printf("Frame within window\n");
  368. #endif
  369.         cb->rxbufs[rxbuf].occupied = 1;
  370.         cb->rxbufs[rxbuf].data = bp;
  371.                 
  372.         for(rxbuf = cb->rxpected % window; cb->rxbufs[rxbuf].occupied;
  373.              rxbuf = cb->rxpected % window){
  374. #ifdef NR4DEBUG
  375.             printf("Removing frame from buffer %d\n", rxbuf);
  376. #endif
  377.             newdata = 1;
  378.             cb->rxbufs[rxbuf].occupied = 0;
  379.             append(&cb->rxq,cb->rxbufs[rxbuf].data);
  380.             cb->rxbufs[rxbuf].data = NULLBUF;
  381.             cb->rxpected = (cb->rxpected + 1) & NR4SEQMASK;
  382.             cb->rxpastwin = (cb->rxpastwin + 1) & NR4SEQMASK;
  383.         }
  384.         if(newdata){
  385.             cb->naksent = 0;    /* OK to send NAKs again */
  386.             if(cb->r_upcall != NULLVFP)
  387.                 (*cb->r_upcall)(cb,len_p(cb->rxq));
  388.  
  389.             /* Now that our upcall has had a shot at the queue, */
  390.             /* see if it's past the queue length limit.  If so, */
  391.             /* go into choked mode (i.e. flow controlled). */
  392.  
  393.             if(len_p(cb->rxq) > Nr4qlimit){
  394.                 cb->qfull = 1;
  395.                 nr4ackit((char *)cb);    /* Tell `em right away */
  396.             } else
  397.                 start_timer(&cb->tack);
  398.         }
  399.     } else     /* It's out of the window or we've seen it already */
  400.         free_p(bp);
  401. }
  402.  
  403.  
  404. /* Send the transmit buffer whose sequence number is seq */
  405. void
  406. nr4sbuf(cb, seq)
  407. struct nr4cb *cb;
  408. unsigned seq;
  409. {
  410.     struct nr4hdr hdr;
  411.     struct mbuf *bufbp, *bp;
  412.     unsigned bufnum = seq % cb->window;
  413.     struct timer *t;
  414.     
  415.     /* sanity check */
  416.     if(bufnum >= cb->window){
  417. #ifdef NR4DEBUG
  418.         printf("sbuf: buffer number %u beyond window\n",bufnum);
  419. #endif
  420.         return;
  421.     }
  422.  
  423.     /* Stop the ACK timer, since our sending of the frame is
  424.      * an implied ACK.
  425.      */
  426.     stop_timer(&cb->tack);
  427.     
  428.     /* Duplicate the mbuf, since we have to keep it around
  429.      * until it is acknowledged
  430.      */
  431.     bufbp = cb->txbufs[bufnum].data;
  432.  
  433.     /* Notice that we use copy_p instead of dup_p.  This is because
  434.      * a frame can still be sitting on the AX.25 send queue when it
  435.      * get acknowledged, and we don't want to deallocate its data
  436.      * before it gets sent!
  437.      */
  438.     if((bp = copy_p(bufbp, len_p(bufbp))) == NULLBUF){
  439.         free_mbuf(bp);
  440.         return;
  441.     }
  442.  
  443.     /* Prepare the header */
  444.     if(cb->qfull)                /* are we choked? */
  445.         hdr.opcode = NR4OPINFO | NR4CHOKE;
  446.     else
  447.         hdr.opcode = NR4OPINFO;
  448.     hdr.yourindex = cb->yournum;
  449.     hdr.yourid = cb->yourid;
  450.     hdr.u.info.txseq = (unsigned char)(seq & NR4SEQMASK);
  451.     hdr.u.info.rxseq = cb->rxpected;
  452.     
  453.     /* Send the frame, then set and start the timer */
  454.     nr4sframe(cb->remote.node, &hdr, bp);
  455.  
  456.     t = &cb->txbufs[bufnum].tretry;
  457.     set_timer(t, (1 << cb->blevel) * (2 * cb->mdev + cb->srtt + MSPTICK));
  458.     start_timer(t);
  459. }
  460.  
  461. /* Check to see if any of our frames have been ACKed */
  462.  
  463. static void
  464. nr4ackours(cb, seq, gotchoke)
  465. struct nr4cb *cb;
  466. unsigned seq;
  467. int gotchoke;    /* The choke flag is set in the received frame */
  468. {
  469.     unsigned txbuf;
  470.     struct timer *t;
  471.     
  472.     /* If we are choked, there is nothing in the send window
  473.      * by definition, so we can just return.
  474.      */
  475.     if(cb->choked)
  476.         return;
  477.         
  478.     /* Adjust seq to point to the frame being ACK'd, not the one
  479.      * beyond it, which is how it arrives.
  480.      */
  481.     seq = (seq - 1) & NR4SEQMASK;
  482.  
  483.     /* Free up all the ack'd frames, and adjust the round trip
  484.      * timing stuff
  485.      */
  486.     while (nr4between(cb->ackxpected, seq, cb->nextosend)){
  487. #ifdef NR4DEBUG
  488.         printf("Sequence # %u acknowledged\n", seq);
  489. #endif
  490.         cb->nbuffered--;
  491.         txbuf = cb->ackxpected % cb->window;
  492.         free_mbuf(cb->txbufs[txbuf].data);
  493.         cb->txbufs[txbuf].data = NULLBUF;
  494.         cb->ackxpected = (cb->ackxpected + 1) & NR4SEQMASK;
  495.  
  496.         /* Round trip time estimation, cribbed from TCP */
  497.         if(cb->txbufs[txbuf].retries == 0){
  498.             /* We only sent this one once */
  499.             int32 rtt;
  500.             int32 abserr;
  501.  
  502.             t = &cb->txbufs[txbuf].tretry;
  503.             /* get our rtt in msec */
  504.             rtt = (dur_timer(t) - read_timer(t)) * MSPTICK;
  505.             abserr = (rtt > cb->srtt) ? rtt - cb->srtt : cb->srtt - rtt;
  506.             cb->srtt = (cb->srtt * 7 + rtt) >> 3;
  507.             cb->mdev = (cb->mdev * 3 + abserr) >> 2;
  508.  
  509.             /* Reset the backoff level */
  510.             cb->blevel = 0;
  511.         }
  512.         stop_timer(&cb->txbufs[txbuf].tretry);
  513.     }    
  514.     /* Now we recalculate tmax, the maximum number of retries for
  515.      * any frame in the window.  tmax is used as a baseline to
  516.      * determine when the window has reached a new high in retries.
  517.      * We don't want to increment blevel for every frame that times
  518.      * out, since that would lead to us backing off too fast when
  519.      * all the frame timers expired at around the same time.
  520.      */
  521.     cb->txmax = 0;
  522.     
  523.     for(seq = cb->ackxpected;
  524.          nr4between(cb->ackxpected, seq, cb->nextosend);
  525.          seq = (seq + 1) & NR4SEQMASK)
  526.         if(cb->txbufs[seq % cb->window].retries > cb->txmax)
  527.             cb->txmax = cb->txbufs[seq % cb->window].retries;
  528.  
  529.     /* This is kind of a hack.  This function is called under
  530.      * three different conditions:  either we are choked, in
  531.      * which case we return immediately, or we are not choked,
  532.      * in which case we proceed normally to keep the send
  533.      * window full, or we have seen the choke flag for the first
  534.      * time.  In the last case, gotchoke is true while cb->choked
  535.      * is false.  We want to process any acknowledgments of existing
  536.      * frames in the send window before we purge it, while at the
  537.      * same time we don't want to take anything else off the txq
  538.      * or send it out.  So, in the third case we listed, we return
  539.      * now since we've processed the ACK.
  540.      */
  541.     
  542.     if(gotchoke)
  543.         return;
  544.         
  545.     nr4output(cb);            /* yank stuff off txq and send it */
  546.  
  547.     /* At this point, either the send window is full, or
  548.      * nr4output() didn't find enough on the txq to fill it.
  549.      * If the window is not full, then the txq must be empty,
  550.      * and we'll make a tx upcall
  551.      */
  552.     if(cb->nbuffered < cb->window && cb->t_upcall != NULLVFP)
  553.         (*cb->t_upcall)(cb, (int16)((cb->window - cb->nbuffered) * NR4MAXINFO));
  554.  
  555. }
  556.  
  557.  
  558. /* If the send window is open and there are frames on the txq,
  559.  * move as many as possible to the transmit buffers and send them.
  560.  * Return the number of frames sent.
  561.  */
  562. int
  563. nr4output(cb)
  564. struct nr4cb *cb;
  565. {
  566.     int numq, i;
  567.     struct mbuf *bp;
  568.     struct nr4txbuf *tp;
  569.  
  570.     /* Are we in the proper state? */
  571.     if(cb->state != NR4STCON || cb->choked)
  572.         return 0;        /* No sending if not connected */
  573.                     /* or if choked */
  574.         
  575.     /* See if the window is open */
  576.     if(cb->nbuffered >= cb->window)
  577.         return 0;
  578.  
  579.     numq = len_q(cb->txq);
  580.     
  581. #ifdef NR4DEBUG
  582.     printf("nr4output: %d packets on txq\n", numq);
  583. #endif
  584.     
  585.     for(i = 0; i < numq; i++){
  586.         bp = dequeue(&cb->txq);
  587. #ifdef NR4DEBUG
  588.         if(len_p(bp) > NR4MAXINFO){    /* should be checked higher up */
  589.             printf("Upper layers queued too big a buffer\n");
  590.             continue;
  591.         }
  592. #endif
  593.         /* Set up and send buffer */
  594.         tp = &cb->txbufs[cb->nextosend % cb->window];
  595.         tp->retries = 0;
  596.         tp->data = bp;
  597.         nr4sbuf(cb, cb->nextosend);
  598.  
  599.         /* Update window and buffered count */
  600.         cb->nextosend = (cb->nextosend + 1) & NR4SEQMASK;
  601.         if(++cb->nbuffered >= cb->window)
  602.             break;
  603.     }
  604.     return i;        
  605. }
  606.  
  607. void
  608. nr4state(cb, newstate)
  609. struct nr4cb *cb;
  610. int newstate;
  611. {
  612.     int i;
  613.     int oldstate = cb->state;
  614.     
  615.     cb->state = newstate;
  616.  
  617.     switch(cb->state){
  618.     case NR4STDPEND:
  619.         stop_timer(&cb->tchoke);
  620.  
  621.         /* When we request a disconnect, we lose the contents of
  622.          * our transmit queue and buffers, but we retain our ability
  623.          * to receive any packets in transit until a disconnect
  624.          * acknowledge arrives
  625.          */
  626.         free_q(&cb->txq);
  627.         
  628.         for(i = 0; i < cb->window; i++){
  629.             free_mbuf(cb->txbufs[i].data);
  630.             cb->txbufs[i].data = NULLBUF;
  631.             stop_timer(&cb->txbufs[i].tretry);
  632.         }
  633.         
  634.         /* Tidy up stats: roll the top window pointer back
  635.          * and reset nbuffered to reflect this.  Not really
  636.          * necessary, but leads to a bit more truth telling
  637.          * in the status displays.
  638.          */
  639.         cb->nextosend = cb->ackxpected;
  640.         cb->nbuffered = 0;
  641.         break;
  642.       case NR4STDISC:
  643.         stop_timer(&cb->tchoke);
  644.         stop_timer(&cb->tack);
  645.         stop_timer(&cb->tcd);
  646.  
  647.         /* We don't clear the rxq, since the state change upcall
  648.          * may pull something off of it at the last minute.
  649.          */
  650.         free_q(&cb->txq);
  651.  
  652.         /* The following loop will only be executed if the
  653.          * window was set, since when the control block is
  654.          * calloc'd the window field gets a 0 in it.  This
  655.          * protects us from dereferencing an unallocated
  656.          * window buffer pointer
  657.          */
  658.         for(i = 0; i < cb->window; i++){
  659.             free_mbuf(cb->rxbufs[i].data);
  660.             cb->rxbufs[i].data = NULLBUF;
  661.             free_mbuf(cb->txbufs[i].data);
  662.             cb->txbufs[i].data = NULLBUF;
  663.             stop_timer(&cb->txbufs[i].tretry);
  664.         }
  665.         break;
  666.     }
  667.  
  668.     if(oldstate != newstate && cb->s_upcall != NULLVFP)
  669.         (*cb->s_upcall)(cb, oldstate, newstate);
  670.  
  671.     /* We take responsibility for deleting the circuit
  672.      * descriptor.  Don't do this anywhere else!
  673.      */
  674.     if(newstate == NR4STDISC)
  675.         free_n4circ(cb);
  676. }
  677.  
  678. /* Process NAKs.  seq indicates the next frame expected by the
  679.  * NAK'ing station.
  680.  */
  681.  
  682. static void
  683. nr4gotnak(cb, seq)
  684. struct nr4cb *cb;
  685. unsigned seq;
  686. {
  687.     if(nr4between(cb->ackxpected, seq, cb->nextosend))
  688.         nr4sbuf(cb, seq);
  689. }
  690.  
  691.  
  692. /* This is called when we first get a CHOKE indication from the
  693.  * remote.  It purges the send window and sets the choke timer.
  694.  */
  695.  
  696. static void
  697. nr4choke(cb)
  698. struct nr4cb *cb;
  699. {
  700.     unsigned seq;
  701.     struct mbuf *q, *bp;
  702.     struct nr4txbuf *t;
  703.  
  704.     q = cb->txq;
  705.  
  706.     /* We purge the send window, returning the buffers to the
  707.      * txq in the proper order.
  708.      */
  709.     for(seq = (cb->nextosend - 1) & NR4SEQMASK;
  710.          nr4between(cb->ackxpected, seq, cb->nextosend);
  711.          seq = (seq - 1) & NR4SEQMASK){
  712.  
  713.         t = &cb->txbufs[seq % cb->window];
  714.         stop_timer(&t->tretry);
  715.         bp = t->data;
  716.         t->data = NULLBUF;
  717.         enqueue(&bp, q);    /* prepend this packet to the queue */
  718.         q = bp;
  719.      }
  720.  
  721.     cb->nextosend = cb->ackxpected;    /* close the window */
  722.     cb->nbuffered = 0;        /* nothing in the window */
  723.     cb->txq = q;            /* Replace the txq with the one that has */
  724.                     /* the purged packets prepended */
  725.     cb->choked = 1;        /* Set the choked flag */
  726.  
  727.     start_timer(&cb->tchoke);
  728. }
  729.